#pragma once
#include <chrono>
#include <boost/filesystem.hpp>
#include <cstdint>
#include <exception>
#include "nlohmann/json.hpp"
#include "server/config/config.h"
#include "state_machin_define.h"

namespace ArrowWebCodeView
{
namespace SessionMachine
{

class StateSendFileData : public StateBase
{

private:
    using Data = StateBase::Data;
    using StateEnum = StateBase::StateEnum;
    using Msg = StateBase::Msg;

public:
    StateSendFileData() {}

public:
    virtual ~StateSendFileData() {}

    /**
     * @description: 初始化 创建状态的时候调用一次
     * @param {AreaMachineData&} data
     * @return {*}
     */
    virtual void Init(const Data& data)
    {
    }

    /**
     * @description: 当从其他状态迁移到当前状态调用
     * @param {AreaMachineData*} pData
     * @return {*}
     */
    virtual void Start(Data* pData)
    {
    }

    /**
     * @description: 处理消息
     * @param {Data*} pData
     * @param {Msg} msg
     * @return {*}
     */    
    virtual StateEnum HandleMsg(Data* pData, Msg msg, const std::string& strMsg, std::string& strResult)
    {
        if(msg != Msg::File)
        {
            return StateEnum::SendFileData;
        }


        boost::filesystem::path path(strMsg);

        try
        {
            nlohmann::json jResult;
            jResult["cmd"] = MsgEnumStr::ItemStr(msg);
            jResult["result"]["folder"] = path.parent_path().string();
            jResult["result"]["filename"] = path.filename().string();
            
            std::uintmax_t fileSize = boost::filesystem::file_size(path);
            if(fileSize > static_cast<std::uintmax_t >(AppConfig::Instance()->MaxFileSize()))
            {
                jResult["result"]["data"] = "file size too large";
            }
            else if(Arrow::Other::IsBinaryFile(strMsg))
            {
                jResult["result"]["data"] = "file is binary";
            }
            else
            {
                std::ifstream fRead(strMsg, std::ios_base::in);
                std::stringstream buffer;
                buffer << fRead.rdbuf();
                fRead.close();
                jResult["result"]["data"] = buffer.str();
            }
            strResult = jResult.dump();

            ARROW_LOG_INFO_FMT("getf file data %s success", strMsg.c_str());
        }
        catch (std::exception& e)
        {
            nlohmann::json jResult;
            jResult["cmd"] = MsgEnumStr::ItemStr(msg);
            jResult["result"]["folder"] = path.parent_path().string();
            jResult["result"]["filename"] = path.filename().string();
            jResult["result"]["data"] = "read file fail";
            strResult = jResult.dump();
            ARROW_LOG_ERROR_FMT("getf file data %s to json fail error:%s", strMsg.c_str(), e.what());
        }

        m_pContext->ChangeState(StateEnum::RecvPath);
        return StateEnum::RecvPath;
    }

    /**
     * @description: 处理定时消息
     * @param {AreaMachineData*} pData
     * @return {*}
     */    
    virtual StateEnum Timer(Data* pData)
    {
        return State();
    }

    /**
     * @description: 当前状态
     * @return {*}
     */
    virtual StateEnum State()
    {
        return StateEnum::SendFileData;
    }

    virtual void Context(ContextType* pContext)
    {
        m_pContext = pContext;
    }

private:
    ContextType* m_pContext = nullptr;
};
}
}